﻿using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace SchemaGen.Xsd
{
    public enum SequenceIndicator
    {
        /// <summary>
        /// Specifies that the child elements can appear in any order, and that each child element must occur only once
        /// </summary>
        All,

        /// <summary>
        /// Allows only one of the elements to be present within the containing element
        /// </summary>
        Choice,

        /// <summary>
        /// Specifies that the child elements must appear in a sequence. Each child element can occur from 0 to any number of times
        /// </summary>
        Sequence
    }

    public class SComplexType : IComplexType
    {
        public string Name { get; set; }
        public List<SEntityBase> Content { get; private set; }
        public SequenceIndicator SequenceIndicator { get; set; }
        public string Extends { get; set; }

        // Probably best not to allow this boolean
        // public bool Mixed { get; set; }

        public SComplexType()
            : this(SequenceIndicator.Sequence) { }

        public SComplexType(SequenceIndicator sequenceIndicator)
        {
            Content = new List<SEntityBase>();
            SequenceIndicator = sequenceIndicator;
        }

        internal XElement Create()
        {
            XName sequenceName = null;

            switch (SequenceIndicator)
            {
                case SequenceIndicator.All:
                    sequenceName = SNames.Elements.All;
                    break;
                case SequenceIndicator.Choice:
                    sequenceName = SNames.Elements.Choice;
                    break;
                case SequenceIndicator.Sequence:
                    sequenceName = SNames.Elements.Sequence;
                    break;
            }

            var result = new XElement(SNames.Elements.ComplexType);
            if (Name != null) result.Add(new XAttribute("name", Name));

            var container = result;

            if (Extends != null)
            {
                container =
                    new XElement(SNames.Elements.Extension,
                        new XAttribute("base", Extends));

                result.Add(new XElement(SNames.Elements.ComplexContent, container));
            }

            if (Content.Any(a => !a.GetType().Equals(typeof(SAttribute))))
            {
                container.Add(new XElement(sequenceName, Content
                    .Where(c => c.GetType() != typeof(SAttribute))
                    .Select(e => e.Create())));
            }

            container.Add(Content
                .Where(c => c.GetType().Equals(typeof(SAttribute)))
                .Select(a => a.Create()));
            
            return result;
        }

        #region IComplexType

        public void Add(SEntityBase entity) { Content.Add(entity); }
        public void Clear() { Content.Clear(); }
        public bool Contains(SEntityBase entity) { return Content.Contains(entity); }
        public void CopyTo(SEntityBase[] array, int arrayIndex) { Content.CopyTo(array, arrayIndex); }
        public int Count { get { return Content.Count; } }
        public bool IsReadOnly { get { return false; } }
        public bool Remove(SEntityBase entity) { return Content.Remove(entity); }
        public IEnumerator<SEntityBase> GetEnumerator() { return Content.GetEnumerator(); }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return Content.GetEnumerator(); }

        #endregion
    }
}
